package com.hyt.it.ogt.ksmonitor.statistics.util;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
import com.fasterxml.jackson.databind.module.SimpleModule;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 常用工具类
 * Created by zbk.
 * E-mail: zhangbk@hyxt.com
 * Date: 2015/10/12
 */
public class BeanUtils {
    /**
     * 获取对象属性，返回一个字符串数组
     *
     * @param o 对象
     * @return String[] 字符串数组
     */
    public static String[] getFiledName(Object o) {
        Field[] fields = o.getClass().getDeclaredFields();
        String[] fieldNames = new String[fields.length];
        for (int i = 0; i < fields.length; i++) {
            fieldNames[i] = fields[i].getName();
        }
        return fieldNames;
    }

    /**
     * 将一个Map对象转化为一个Bean.
     * 说明：只针对有一级属性的bean
     *
     * @param map   待转换的Map
     * @param clazz 转换后的Bean
     * @return 转换出来的Bean
     */
    public static Object convertMapToBean(Map<String, ? extends Object> map, Class<?> clazz) throws IntrospectionException, IllegalAccessException, InstantiationException, InvocationTargetException {
        BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
        Object obj = clazz.newInstance();
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        int len = propertyDescriptors.length;
        String propertyName = "";
        PropertyDescriptor descriptor = null;
        for (int i = 0; i < len; i++) {
            descriptor = propertyDescriptors[i];
            propertyName = descriptor.getName();
            if (map.containsKey(propertyName)) {
                Object value = map.get(propertyName);
                Object[] args = new Object[1];
                args[0] = value;
                descriptor.getWriteMethod().invoke(obj, args);
            }
        }
        return obj;
    }

    /**
     * 将一个Bean对象转化为一个Map.
     * 说明：只针对有一级属性的bean
     *
     * @param bean 要转化的Bean对象
     * @return 转化出来的Map对象
     * @throws IntrospectionException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    public static <K,V> Map<K,V> convertBeanToMap(Object bean) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        Class type = bean.getClass();
        Map<K,V> returnMap = new HashMap<K,V>();
        BeanInfo beanInfo = Introspector.getBeanInfo(type);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        PropertyDescriptor descriptor = null;
        int len = propertyDescriptors.length;
        String propertyName = "";
        for (int i = 0; i < len; i++) {
            descriptor = propertyDescriptors[i];
            propertyName = descriptor.getName();
            if (!propertyName.equals("class")) {
                Method readMethod = descriptor.getReadMethod();
                Object result = readMethod.invoke(bean, new Object[0]);
                if (result != null) {
                    returnMap.put((K)propertyName, (V)result);
                } else {
                    returnMap.put((K)propertyName, null);
                }
            }
        }
        return returnMap;
    }

    /**
     * json格式转换为bean对象
     *
     * @param json  json字符串
     * @param clazz bean对象
     * @return
     * @throws IOException
     */
    public static <T> T json2Bean(String json, Class<T> clazz) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(json, clazz);
    }


    /**
     * json格式转换为bean对象
     *
     * @param json  json字符串
     * @param clazz bean对象
     * @return
     * @throws IOException
     */
    public static <T> T json2Bean(String json, Class<T> clazz,Class<?> ... elementClasses) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        JavaType javaType = objectMapper.getTypeFactory().constructParametrizedType(clazz,clazz, elementClasses);
        return objectMapper.readValue(json, javaType);
    }

    /**
     * json格式转换为list对象
     *
     * @param json  json字符串
     * @param clazz bean对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> json2List(String json, Class<T> clazz) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        JavaType javaType = objectMapper.getTypeFactory().constructParametrizedType(ArrayList.class,ArrayList.class, clazz);
        return objectMapper.readValue(json, javaType);
    }

    /**
     * json格式转换为bean 集合对象
     *
     * @param json  json字符串
     * @param collectionClass 集合bean对象
     * @param elementClasses bean对象
     * @return
     * @throws IOException
     */
    public static <T>  T json2BeanCollection(String json, Class<T> collectionClass,Class<?> ... elementClasses) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        JavaType javaType = objectMapper.getTypeFactory().constructParametrizedType(collectionClass,collectionClass, elementClasses);
        return objectMapper.readValue(json, javaType);
    }

    public static <T, E extends Enum> T json2BeanWithEnums(String json, Class<T> clazz, final Class<E>... enums) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        for (final Class<E> e : enums) {
            module.addDeserializer(e, new JsonDeserializer<E>() {
                @Override
                public E deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
                    JsonNode node = p.getCodec().readTree(p);
                    String name = node.get("name").asText();
                    return (E) Enum.valueOf(e, name);
                }
            });
            mapper.registerModule(module);
        }
        module.addDeserializer(Enum.class, new JsonDeserializer<Enum>() {
            @Override
            public Enum deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
                JsonNode node = p.getCodec().readTree(p);
                return null;
            }
        });
        mapper.registerModule(module);
	    mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
	    mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
	    mapper.setVisibility(VisibilityChecker.Std.defaultInstance().withFieldVisibility(JsonAutoDetect.Visibility.ANY));
        return mapper.readValue(json, clazz);
    }


    /**
     * bean对象转换为json字符串
     *
     * @param bean bean对象
     * @return
     * @throws Exception
     */
    public static String bean2Json(Object bean) throws Exception {
        return null == bean ? null : new ObjectMapper().writeValueAsString(bean);
    }


}
